

/*
*/
module riscv_inst_ram(
    input         rst,
    input         data_clk,
    input         data_ce,
    input         MemWr,
    input  [31:0] AddrIn,
    input  [31:0] DataIn,
    output [31:0] DataOut,

    input         inst_clk,
    input         inst_ce,
    input  [31:0] inst_addr,
    output [31:0] inst_data
);

dpram inst_ram(
	.doa(DataOut), .dia(DataIn), .addra(AddrIn[12:2]), .cea(data_ce), .clka(data_clk), .wea(MemWr),
	.dob(inst_data), .dib(32'h0000_0000), .addrb(inst_addr[12:2]), .ceb(inst_ce), .clkb(inst_clk), .web(1'b0)
);

endmodule

module riscv_data_ram(
    input        rst,
    input        clk,
    input        ce,
    input [2:0]  MemOp,
    input        MemWr,
    input [31:0] AddrIn,
    input [31:0] DataIn,
    output reg [31:0] DataOut
);
    reg [31:0] Addr;

    wire [7:0] doa0;
    reg [7:0] dia0;
    reg [11:0] addra0;
    reg wea0;
    reg cea0;

    wire [7:0] doa1;
    reg [7:0] dia1;
    reg [11:0] addra1;
    reg wea1;
    reg cea1;

    wire [7:0] doa2;
    reg [7:0] dia2;
    reg [11:0] addra2;
    reg wea2;
    reg cea2;

    wire [7:0] doa3;
    reg [7:0] dia3;
    reg [11:0] addra3;
    reg wea3;
    reg cea3;

    reg dr_cea0;
    reg dr_cea1;
    reg dr_cea2;
    reg dr_cea3;

    reg [7:0] doa_byte;
    reg [15:0] doa_half;
    reg [31:0] doa_word;
    reg [31:0] doa_out;

    data_ram0 data_ram_u0(
        .doa(doa0),
        .dia(dia0),
        .addra(addra0),
        .wea(wea0),
        .cea(dr_cea0),
        .clka(clk)
    );

    data_ram1 data_ram_u1(
        .doa(doa1),
        .dia(dia1),
        .addra(addra1),
        .wea(wea1),
        .cea(dr_cea1),
        .clka(clk)
    );

    data_ram2 data_ram_u2(
        .doa(doa2),
        .dia(dia2),
        .addra(addra2),
        .wea(wea2),
        .cea(dr_cea2),
        .clka(clk)
    );

    data_ram3 data_ram_u3(
        .doa(doa3),
        .dia(dia3),
        .addra(addra3),
        .wea(wea3),
        .cea(dr_cea3),
        .clka(clk)
    );

    always @(*) begin
        Addr = AddrIn;
        dr_cea0 = cea0 & ce;
        dr_cea1 = cea1 & ce;
        dr_cea2 = cea2 & ce;
        dr_cea3 = cea3 & ce;
    end
 
    always @(*) begin
        if (MemWr==1'b1) begin              //处理写
            case (MemOp)
                3'b000: begin               //单字节操作
                    case (Addr[1:0])
                        2'b00: begin
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2];
                            dia0[7:0] <= DataIn[7:0];
                            cea1 <= 0;
                            cea2 <= 0;
                            cea3 <= 0;
                            wea1 <= 0;
                            wea2 <= 0;
                            wea3 <= 0;
                        end
                        2'b01: begin
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            dia1[7:0] <= DataIn[7:0];
                            cea0 <= 0;
                            cea2 <= 0;
                            cea3 <= 0;
                            wea0 <= 0;
                            wea2 <= 0;
                            wea3 <= 0;
                        end
                        2'b10: begin
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            dia2[7:0] <= DataIn[7:0];
                            cea0 <= 0;
                            cea1 <= 0;
                            cea3 <= 0;
                            wea0 <= 0;
                            wea1 <= 0;
                            wea3 <= 0;
                        end
                        2'b11: begin
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[7:0];
                            cea0 <= 0;
                            cea1 <= 0;
                            cea2 <= 0;
                            wea0 <= 0;
                            wea1 <= 0;
                            wea2 <= 0;
                        end
                    endcase
                end
                3'b001: begin                       //两字节操作
                    case (Addr[1:0])
                        2'b00: begin
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2];
                            dia0[7:0] <= DataIn[7:0];
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            dia1[7:0] <= DataIn[15:8];
                            cea2 <= 0;
                            cea3 <= 0;
                            wea2 <= 0;
                            wea3 <= 0;
                        end

                        2'b01: begin                //非对其两字节写
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            dia1[7:0] <= DataIn[7:0];
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            dia2[7:0] <= DataIn[15:8];
                            cea0 <= 0;
                            cea3 <= 0;
                            wea0 <= 0;
                            wea3 <= 0;
                        end

                        2'b10: begin
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            dia2[7:0] <= DataIn[7:0];
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[15:8];
                            cea0 <= 0;
                            cea1 <= 0;
                            wea0 <= 0;
                            wea1 <= 0;
                        end
                        2'b11: begin                //非对其
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[7:0];
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            dia0[7:0] <= DataIn[15:8];
                            cea1 <= 0;
                            cea2 <= 0;
                            wea1 <= 0;
                            wea2 <= 0;
                        end
                     endcase
                end
                default: begin                      //4字节操作
                    case (Addr[1:0])
                        2'b00: begin
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2];
                            dia0[7:0] <= DataIn[7:0];
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            dia1[7:0] <= DataIn[15:8];
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            dia2[7:0] <= DataIn[23:16];
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[31:24];
                        end
                        2'b01: begin
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            dia1[7:0] <= DataIn[7:0];
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            dia2[7:0] <= DataIn[15:8];
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[23:16];
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            dia0[7:0] <= DataIn[31:24];
                        end
                        2'b10: begin
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            dia2[7:0] <= DataIn[7:0];
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[15:8];
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            dia0[7:0] <= DataIn[23:16];
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2] + 10'h1;
                            dia1[7:0] <= DataIn[31:24];
                        end
                        2'b11: begin
                            wea3 <= 1'b1;
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            dia3[7:0] <= DataIn[7:0];
                            wea0 <= 1'b1;
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            dia0[7:0] <= DataIn[15:8];
                            wea1 <= 1'b1;
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2] + 10'h1;
                            dia1[7:0] <= DataIn[23:16];
                            wea2 <= 1'b1;
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2] + 10'h1;
                            dia2[7:0] <= DataIn[31:24];
                        end
                    endcase
                end
            endcase //case(MemOp)
        end else begin                      //下面是处理读操作
            wea0 <= 1'b0;
            wea1 <= 1'b0;
            wea2 <= 1'b0;
            wea3 <= 1'b0;
            case (MemOp)
                3'b000, 3'b100: begin           //单字节，扩展到32bits整数
                    case (Addr[1:0])
                        2'b00:  begin
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2];
                            doa_byte <= doa0[7:0];
                            cea1 <= 0;
                            cea2 <= 0;
                            cea3 <= 0;
                        end
                        2'b01:  begin
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            doa_byte <= doa1[7:0];
                            cea0 <= 0;
                            cea2 <= 0;
                            cea3 <= 0;
                        end
                        2'b10:  begin
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            doa_byte <= doa2[7:0];
                            cea0 <= 0;
                            cea1 <= 0;
                            cea3 <= 0;
                        end
                        2'b11:  begin
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_byte <= doa3[7:0];
                            cea0 <= 0;
                            cea1 <= 0;
                            cea2 <= 0;
                        end
                    endcase
                end

                3'b001, 3'b101: begin                   // 双字节，扩展到32bits整数
                    case (Addr[1:0])
                        2'b00: begin
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2];
                            doa_half[7:0] <= doa0[7:0];
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            doa_half[15:8] <= doa1[7:0];
                            cea2 <= 0;
                            cea3 <= 0;
                        end
                        2'b01: begin                    // 非对其
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            doa_half[7:0] <= doa1[7:0];
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            doa_half[15:8] <= doa2[7:0];
                            cea0 <= 0;
                            cea3 <= 0;
                        end
                        2'b10: begin
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            doa_half[7:0] <= doa2[7:0];
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_half[15:8] <= doa3[7:0];
                            cea0 <= 0;
                            cea1 <= 0;
                        end 
                        2'b11: begin                    // 非对其
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_half[7:0] <= doa3[7:0];
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            doa_half[15:8] <= doa0[7:0];
                            cea1 <= 0;
                            cea2 <= 0;
                        end 
                     endcase
                end

                3'b010: begin                   // 32bits整个word装入，无需扩展
                    case (Addr[1:0])
                        2'b00: begin
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2];
                            doa_word[7:0] <=   doa0[7:0];
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            doa_word[15:8] <=  doa1[7:0];
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            doa_word[23:16] <= doa2[7:0];
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_word[31:24] <= doa3[7:0];
                        end
                        2'b01: begin
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2];
                            doa_word[7:0]  <=  doa1[7:0];
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            doa_word[15:8] <=  doa2[7:0];
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_word[23:16] <= doa3[7:0];
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            doa_word[31:24] <= doa0[7:0];
                        end
                        2'b10: begin
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2];
                            doa_word[7:0] <=   doa2[7:0];
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_word[15:8] <=  doa3[7:0];
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            doa_word[23:16] <= doa0[7:0];
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2] + 10'h1;
                            doa_word[31:24] <= doa1[7:0];
                        end
                        2'b11: begin
                            cea3 <= 1'b1;
                            addra3 <= Addr[11:2];
                            doa_word[7:0] <=   doa3[7:0];
                            cea0 <= 1'b1;
                            addra0 <= Addr[11:2] + 10'h1;
                            doa_word[15:8] <=  doa0[7:0];
                            cea1 <= 1'b1;
                            addra1 <= Addr[11:2] + 10'h1;
                            doa_word[23:16] <= doa1[7:0];
                            cea2 <= 1'b1;
                            addra2 <= Addr[11:2] + 10'h1;
                            doa_word[31:24] <= doa2[7:0];
                        end
                    endcase
                end
            endcase
        end 
    end

    //处理符号扩展和非符号扩展
    always @(*) begin
        if (MemWr == 1'b0) begin    //如果是读
            case (MemOp)
                3'b000: begin   //带符号扩展
                    doa_out = {doa_byte[7:7] == 1'b1 ? 24'hffffff : 24'h000000, doa_byte[7:0]};
                end
                3'b001: begin    
                    doa_out = {doa_half[15:15] == 1'b1 ? 16'hffff : 16'h0000, doa_half[15:0]};
                end
                3'b100: begin   //无符号扩展
                    doa_out = {24'h000000, doa_byte[7:0]};
                end
                3'b101: begin
                    doa_out = {16'h0000, doa_half[15:0]};
                end
                default: begin
                    doa_out = doa_word;
                end
            endcase
        end
        else begin
        	doa_out = doa_word;
        end
    end

    always @(*) begin
        if (MemWr == 1'b0 && ce==1'b1) begin
            DataOut = doa_out;
        end else begin
            DataOut = 32'hzzzz_zzzz;
        end
    end

endmodule

